//
// CAnalogInputFilters.cpp
//

/*-----------------------------------------------------*\
			HQ Tech, Make Technology Easy!       
 More information, please go to http://hqtech.nease.net.
/*-----------------------------------------------------*/

#include "stdafx.h"
#include <streams.h>
#include "CAnalogInputFilters.h"

#include "crossbar.h"
#include "CVideoCaptureFilter.h"
#include "CAudioCaptureFilter.h"
#include "COverlayMixerFilter.h"
#include "CSmartTeeFilter.h"
#include "CLiveCapture.h"
#include "UDsUtils.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define _Trying_VMR

////////////////////////////////////////////////////////////////////////
CAnalogInputFilters::CAnalogInputFilters(CDXGraph * inGraph) :
CLiveInputFilters(inGraph),
cNTSCMaskBits(0x0000000f),
cPALMaskBits(0x00100ff0),
cSECAMMaskBits(0x000ff000)
{
	mVideoCapture  = NULL;
	mAudioCapture  = NULL;
	mOverlayMixer  = NULL;
	mCrossbar      = NULL;
	mGraphBuilder  = NULL;
	mHasPreviewPin = TRUE;
}

CAnalogInputFilters::~CAnalogInputFilters()
{
	Release();
	if (mLiveCapture)
	{
		mLiveCapture->SetVMRPreferred(FALSE);
		mLiveCapture->SetImageGrab(TRUE);
	}
}

BOOL CAnalogInputFilters::Create(void)
{
	ASSERT(mGraph);
	ASSERT(mLiveCapture);
	
	HRESULT hr = S_OK;
	mVideoCapture = new CVideoCaptureFilter(mGraph->GetGraph(), 
		mLiveCapture->GetVideoDevice());
	mAudioCapture = new CAudioCaptureFilter(mGraph->GetGraph(), 
		mLiveCapture->GetAudioDevice());
	mSmartTee     = new CSmartTeeFilter(mGraph->GetGraph());
	mOverlayMixer = new COverlayMixerFilter(mGraph->GetGraph());

	BOOL pass = CLiveInputFilters::Create();
	if (pass)
	{
		pass = mVideoCapture->CreateFilter();
	}
	if (pass)
	{
		hr = CoCreateInstance((REFCLSID)CLSID_CaptureGraphBuilder2, 0,
			CLSCTX_INPROC, (REFIID)IID_ICaptureGraphBuilder2, (void **)&mGraphBuilder);
		pass = (mGraphBuilder != NULL);
	}
	if (pass)
	{
		mGraphBuilder->SetFiltergraph(mGraph->GetGraph());
		// Build preview filter chain and filters before the capture filter
		hr = mGraphBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,	&MEDIATYPE_Video, 
			mVideoCapture->GetFilter(), 0, 0);
		if (hr == VFW_S_NOPREVIEWPIN)
		{
			// Faked preview pin (using smart tee)
			mHasPreviewPin = FALSE;
		}
		else if (hr != S_OK)
		{
			pass = FALSE;
		}
	}
	if (pass)
	{
		CreateCrossBar(mVideoCapture->GetFilter());
		// Remove all filters following the capture filter
		UDsUtils::NukeDownstream(mGraph->GetGraph(), mVideoCapture->GetFilter());
		SetVideoConnector(mLiveCapture->GetVideoConnector());
		SetVideoResolution(mLiveCapture->GetVideoResolution());

#ifdef _Trying_VMR
		if (!IsAGPCard() && mLiveCapture->GetWorkMode() == MD_Preview)
		{
			mLiveCapture->SetVMRPreferred(TRUE);
			mLiveCapture->SetImageGrab(FALSE);
		}
		else
		{
			// AGP card doesn't use VMR
			mLiveCapture->SetVMRPreferred(FALSE);
			mLiveCapture->SetImageGrab(TRUE);
		}
#endif // _Trying_VMR

		AdjustOutput();
		CheckSmartTee();
	}

	// Audio part
	if (pass)
	{		
		mAudioCapture->CreateFilter();
		if (mLiveCapture->IsAudioConnectorValid())
		{
			mAudioCapture->SetConnector(mLiveCapture->GetAudioConnector());
		}
		else
		{
			mLiveCapture->SetNotifying(FALSE);
			mLiveCapture->SetAudioConnector(mAudioCapture->GetConnector());
			mLiveCapture->SetNotifying(TRUE);
		}
	}

	return pass;
}

BOOL CAnalogInputFilters::IsAGPCard(void)
{
	if (FindVideoPin(&PIN_CATEGORY_VIDEOPORT))
	{
		return TRUE;
	}
	return FALSE;
}

IPin * CAnalogInputFilters::GetVideoOutPin(void)
{
	// Check smart tee first
	if (mSmartTee && mSmartTee->GetFilter())
	{
		return mSmartTee->GetCapturePin();
	}

	return FindVideoPin(&PIN_CATEGORY_CAPTURE);
}

IPin * CAnalogInputFilters::GetPreviewPin(void)
{
	// If AGP card, provide VP pin
	if (IsAGPCard())
	{
		BOOL pass = TRUE;
		if (!mOverlayMixer->GetFilter())
		{
			mOverlayMixer->CreateFilter();
			IPin * pOut = FindVideoPin(&PIN_CATEGORY_VIDEOPORT);
			IPin * pIn  = mOverlayMixer->GetPin(TRUE);
			pass = mGraph->ConnectFilters(pOut, pIn);
		}
		if (pass)
		{
			return mOverlayMixer->GetPin(FALSE);
		}
	}

	// Check smart tee first
	if (mSmartTee && mSmartTee->GetFilter())
	{
		return mSmartTee->GetPreviewPin();
	}

	IPin * pin = NULL;
	if (mHasPreviewPin)
	{
		pin = FindVideoPin(&PIN_CATEGORY_PREVIEW);
	}
	else
	{
		// If the capture filter has no preview at all
		pin = FindVideoPin(&PIN_CATEGORY_CAPTURE);
	}

	return pin;
}

IPin * CAnalogInputFilters::GetAudioOutPin(void)
{
	if (mAudioCapture->GetFilter())
	{
		return mAudioCapture->GetPin(FALSE);
	}
	return NULL;
}

void CAnalogInputFilters::Release(void)
{
	SAFE_DELETE(mCrossbar);
	SAFE_DELETE(mSmartTee);
	SAFE_DELETE(mOverlayMixer);
	SAFE_DELETE(mVideoCapture);
	SAFE_DELETE(mAudioCapture);
	SAFE_RELEASE(mGraphBuilder);
}

IPin * CAnalogInputFilters::FindVideoPin(const GUID * inCategory)
{
	if (mVideoCapture && mGraphBuilder)
	{
		IPin * pPin = NULL;
		HRESULT hr = mGraphBuilder->FindPin(
				mVideoCapture->GetFilter(), // Pointer to the capture filter.
				PINDIR_OUTPUT,              // Look for an output pin.
				inCategory,
				NULL,                       // Any media type.
				FALSE,                      // Pin can be connected.
				0,                          // Retrieve the first matching pin.
				&pPin                       // Receives a pointer to the pin.
				);
		if (SUCCEEDED(hr))
		{
			pPin->Release();
			return pPin;
		}
	}
	return NULL;
}

BOOL CAnalogInputFilters::CreateCrossBar(IBaseFilter * inFilter)
{
	IEnumPins *	pins = NULL;
	HRESULT hr = inFilter->EnumPins(&pins);
	if (FAILED(hr))
	{
		return FALSE;
	}
	
	IPin * pPin= NULL;
	IKsPropertySet * pKs = NULL;
	ULONG		count    = 0;
	BOOL		found    = FALSE;
	PIN_INFO	pinInfo;

	while (!found && SUCCEEDED(pins->Next(1, &pPin, &count)) && count)
	{
		if (S_OK == pPin->QueryPinInfo(&pinInfo))
		{
			if (pinInfo.dir == PINDIR_INPUT)
			{
				// Is this pin an ANALOGVIDEOIN input pin?
				if (pPin->QueryInterface(IID_IKsPropertySet, (void **)&pKs) == S_OK)
				{
					GUID   guid;
					DWORD  dw = 0;
					if (pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, 0, 0,
						&guid, sizeof(GUID), &dw) == S_OK)
					{
						if (guid == PIN_CATEGORY_ANALOGVIDEOIN)
						{
							found = TRUE;
						}
					}
					pKs->Release();
				}

				if (found)
				{
					SAFE_DELETE(mCrossbar);
					HRESULT hr = S_OK;
					mCrossbar  = new CCrossbar(pPin, &hr);
				}
			}
			pinInfo.pFilter->Release();
		}
		pPin->Release();
	}
	pins->Release();

	return found;
}

AM_MEDIA_TYPE * CAnalogInputFilters::SelectMediaType(void)
{
	// RGB media type is preferred.
	// Preferred sequence: RGB32, RGB24, RGB565, RGB555, YUY2, UYVY
	VIDEO_STREAM_CONFIG_CAPS  pSCC;
	AM_MEDIA_TYPE * pmt = NULL;
	HRESULT hr = S_OK;
	int nCounts, nSize;
	int preferredIndex = -1;
	enum {
		RGB32 = 0, RGB24, RGB565, RGB555, YUY2, UYVY, Unknown
	} currentPreferred, temp;
	currentPreferred = Unknown;

	IAMStreamConfig * pCfg = GetStreamConfig(&PIN_CATEGORY_CAPTURE);
	pCfg->GetNumberOfCapabilities(&nCounts, &nSize);
	for (int i = 0; i < nCounts; i++)
	{
		if (pCfg->GetStreamCaps(i, &pmt, (BYTE *)&pSCC) == S_OK)
		{
			if (pmt->subtype == MEDIASUBTYPE_RGB32)
			{
				temp = RGB32;
			}
			else if (pmt->subtype == MEDIASUBTYPE_RGB24)
			{
				temp = RGB24;
			}
			else if (pmt->subtype == MEDIASUBTYPE_RGB565)
			{
				temp = RGB565;
			}
			else if (pmt->subtype == MEDIASUBTYPE_RGB555)
			{
				temp = RGB555;
			}
			else if (pmt->subtype == MEDIASUBTYPE_YUY2)
			{
				temp = YUY2;
			}
			else if (pmt->subtype == MEDIASUBTYPE_UYVY)
			{
				temp = UYVY;
			}
			else
			{
				temp = Unknown;
			}

			if (temp < currentPreferred)
			{
				currentPreferred = temp;
				preferredIndex   = i;
			}
			DeleteMediaType(pmt);
		}
	}

	// Get the preferred RGB media type
	if (preferredIndex != -1)
	{
		hr = pCfg->GetStreamCaps(preferredIndex, &pmt, (BYTE *)&pSCC);
	}
	else
	{
		hr = pCfg->GetFormat(&pmt);
	}

	return pmt;
}

AM_MEDIA_TYPE * CAnalogInputFilters::SelectMediaTypeForVMR(void)
{
	// Only YUY2, UYVY are preferred.
	VIDEO_STREAM_CONFIG_CAPS  pSCC;
	AM_MEDIA_TYPE * pmt = NULL;
	HRESULT hr = S_OK;
	int nCounts, nSize;
	int preferredIndex = -1;
	enum { YUY2 = 0, UYVY, Unknown } currentPreferred, temp;
	currentPreferred = Unknown;

	IAMStreamConfig * pCfg = GetStreamConfig(&PIN_CATEGORY_CAPTURE);
	pCfg->GetNumberOfCapabilities(&nCounts, &nSize);
	for (int i = 0; i < nCounts; i++)
	{
		if (pCfg->GetStreamCaps(i, &pmt, (BYTE *)&pSCC) == S_OK)
		{
			if (pmt->subtype == MEDIASUBTYPE_YUY2)
			{
				temp = YUY2;
			}
			else if (pmt->subtype == MEDIASUBTYPE_UYVY)
			{
				temp = UYVY;
			}
			else
			{
				temp = Unknown;
			}

			if (temp < currentPreferred)
			{
				currentPreferred = temp;
				preferredIndex   = i;
			}
			DeleteMediaType(pmt);
		}
	}

	if (preferredIndex != -1)
	{
		hr = pCfg->GetStreamCaps(preferredIndex, &pmt, (BYTE *)&pSCC);
	}

	return pmt;
}

// Adjust capture and preview (if has one) output pins' media type
void CAnalogInputFilters::AdjustOutput(void)
{
	HRESULT  hr         = S_OK;
	AM_MEDIA_TYPE * pmt = NULL;

#ifdef _Trying_VMR
	if (mLiveCapture->IsVMRPreferred())
	{
		pmt = SelectMediaTypeForVMR();
	}
#endif // _Trying_VMR
	if (!pmt)
	{
		pmt = SelectMediaType();
	}

	LONGLONG avgTimePerFrame = 400000;  // 25fps
	if (GetVideoResolution() == SR_NTSC)
	{
		avgTimePerFrame = 333667;       // 29.97fps
	}

	if (pmt)
	{
		if (pmt->formattype == FORMAT_VideoInfo) 
		{
			long width, height;
			mLiveCapture->GetImageSize(&width, &height);

			VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pmt->pbFormat;
			pvi->AvgTimePerFrame       = avgTimePerFrame;
			pvi->bmiHeader.biWidth     = width;
			pvi->bmiHeader.biHeight    = height;
			pvi->bmiHeader.biSizeImage = width * height * pvi->bmiHeader.biBitCount / 8;
			
			IAMStreamConfig * pCfg = GetStreamConfig(&PIN_CATEGORY_CAPTURE);
			hr = pCfg->SetFormat(pmt);
			if (mHasPreviewPin)
			{
				pCfg = GetStreamConfig(&PIN_CATEGORY_PREVIEW);
				hr = pCfg->SetFormat(pmt);
			}
		}
		DeleteMediaType(pmt);
	}
}

// Just demo:
// Adjust output image size to max!
void CAnalogInputFilters::AdjustOutputToMax(void)
{
	VIDEO_STREAM_CONFIG_CAPS  pSCC;
	AM_MEDIA_TYPE *   pmt  = NULL;
	LONGLONG avgTimePerFrame = 400000;  // 25fps
	if (GetVideoResolution() == SR_NTSC)
	{
		avgTimePerFrame = 333667;       // 29.97fps
	}

	IAMStreamConfig * pCfg = GetStreamConfig(&PIN_CATEGORY_CAPTURE);
	// Retrieve the first pin-supported media type
	pCfg->GetStreamCaps(0, &pmt, (BYTE *)&pSCC);
	int  granularityX   = pSCC.OutputGranularityX;
	int  granularityY   = pSCC.OutputGranularityY;
	SIZE minOutputSize  = pSCC.MinOutputSize;
	SIZE maxOutputSize  = pSCC.MaxOutputSize;

	if (pmt && (pmt->formattype == FORMAT_VideoInfo) && 
		(granularityX || granularityY))
	{
		bool   bTurnOfx = false;
		int    nStepx   = 0;
		int    nStepy   = 0;
		int    nCycles  = 0;
		const int nCycleLen = 5;
		long  currentFormat = 0;
		HRESULT hr = S_OK;

		VIDEOINFOHEADER * pvi = (VIDEOINFOHEADER *) pmt->pbFormat;
		pvi->AvgTimePerFrame  = avgTimePerFrame;
		
		do 
		{
			pvi->bmiHeader.biWidth  = maxOutputSize.cx - nStepx * granularityX;
			pvi->bmiHeader.biHeight = maxOutputSize.cy - nStepy * granularityY;
			// If the current size less than the min-size, quit the cycle
			if (pvi->bmiHeader.biWidth < minOutputSize.cx ||
				pvi->bmiHeader.biHeight < minOutputSize.cy)
			{
				break;
			}

			// Change the width and height of output size alternatingly
			nCycles++;
			if (nCycles > nCycleLen)
			{
				bTurnOfx = !bTurnOfx;
				nCycles  = 1;
			}
			if (bTurnOfx)
			{
				nStepx++;
			}
			else
			{
				nStepy++;
			}

			hr = pCfg->SetFormat(pmt);

		} while (hr != S_OK);
	}

	if (pmt)
	{
		DeleteMediaType(pmt);
		pmt = NULL;
	}
}

// Connect a smart tee after Capture pin if necessary
void CAnalogInputFilters::CheckSmartTee(void)
{
	if (!IsAGPCard() && mLiveCapture->GetWorkMode() == MD_Capture)
	{
		BOOL pass = mSmartTee->CreateFilter();
		if (pass && mVideoCapture->GetFilter())
		{
			IPin * pOut = FindVideoPin(&PIN_CATEGORY_CAPTURE);
			IPin * pIn  = mSmartTee->GetInputPin();
			pass = mGraph->ConnectFilters(pOut, pIn);
		}
	}
}

///////////////////////////// Video Connector ////////////////////////////
long CAnalogInputFilters::GetVideoConnectorCount(void)
{
	long count = 0;
	if (mCrossbar)
	{
		mCrossbar->GetInputCount(&count);
	}
	return count;
}

CString CAnalogInputFilters::GetVideoConnectorName(long inIndex)
{
	char connectorName[265];
	strcpy(connectorName, "");
	if (mCrossbar)
	{
		mCrossbar->GetInputName(inIndex, connectorName, 265);
	}
	return connectorName;
}

long CAnalogInputFilters::GetVideoConnectorType(long inIndex)
{
	long physicalType = 0;
	if (mCrossbar)
	{
		mCrossbar->GetInputType(inIndex, &physicalType);
	}
	return physicalType;
}

void CAnalogInputFilters::SetVideoConnector(long inPhysicalType)
{
	if (mCrossbar)
	{
		long count        = 0;
		long physicalType = 0;

		mCrossbar->GetInputCount(&count);
		for (long i = 0; i < count; i++)
		{
			mCrossbar->GetInputType(i, &physicalType);
			if (physicalType == inPhysicalType)
			{
				mCrossbar->SetInputIndex(i);
				break;
			}
		}
	}
}

///////////////////////////// Video Resolution ////////////////////////////
Signal_Resolution CAnalogInputFilters::GetVideoResolution(void)
{
	IAMAnalogVideoDecoder *	pVideoDecoder = GetAnalogDecoder();
	if (pVideoDecoder)
	{
		long format = 0;
		pVideoDecoder->get_TVFormat(&format);
		if (cNTSCMaskBits & format)
		{
			return SR_NTSC;
		}
		else if (cPALMaskBits & format)
		{
			return SR_PAL;
		}
		else if (cSECAMMaskBits & format)
		{
			return SR_SECAM;
		}
	}

	return SR_UNKNOWN;
}

void CAnalogInputFilters::SetVideoResolution(Signal_Resolution inResolution)
{
	long  formatToSet = 0;
	long  allFormats  = GetAllTVFormats();

	// Try every compatible possible resolution
	if (inResolution == SR_NTSC)
	{
		if (AnalogVideo_NTSC_M & allFormats)
		{
			formatToSet = AnalogVideo_NTSC_M;
		}
		else if (AnalogVideo_NTSC_M_J & allFormats)
		{
			formatToSet = AnalogVideo_NTSC_M_J;
		}
		else
		{
			formatToSet = AnalogVideo_NTSC_433;
		}
	}
	else if (inResolution == SR_PAL)
	{
		if (AnalogVideo_PAL_D & allFormats)
		{
			formatToSet = AnalogVideo_PAL_D;
		}
		else if (AnalogVideo_PAL_B & allFormats)
		{
			formatToSet = AnalogVideo_PAL_B;
		}
		else if (AnalogVideo_PAL_H & allFormats)
		{
			formatToSet = AnalogVideo_PAL_H;
		}
		else if (AnalogVideo_PAL_I & allFormats)
		{
			formatToSet = AnalogVideo_PAL_I;
		}
		else if (AnalogVideo_PAL_M & allFormats)
		{
			formatToSet = AnalogVideo_PAL_M;
		}
		else if (AnalogVideo_PAL_N & allFormats)
		{
			formatToSet = AnalogVideo_PAL_N;
		}
		else if (AnalogVideo_PAL_60 & allFormats)
		{
			formatToSet = AnalogVideo_PAL_60;
		}
		else
		{
			formatToSet = AnalogVideo_PAL_N_COMBO;
		}
	}
	else if (inResolution == SR_SECAM)
	{
		if (AnalogVideo_SECAM_B & allFormats)
		{
			formatToSet = AnalogVideo_SECAM_B;
		}
		else if (AnalogVideo_SECAM_D & allFormats)
		{
			formatToSet = AnalogVideo_SECAM_D;
		}
		else if (AnalogVideo_SECAM_G & allFormats)
		{
			formatToSet = AnalogVideo_SECAM_G;
		}
		else if (AnalogVideo_SECAM_H & allFormats)
		{
			formatToSet = AnalogVideo_SECAM_H;
		}
		else if (AnalogVideo_SECAM_K & allFormats)
		{
			formatToSet = AnalogVideo_SECAM_K;
		}
		else if (AnalogVideo_SECAM_K1 & allFormats)
		{
			formatToSet = AnalogVideo_SECAM_K1;
		}
		else if (AnalogVideo_SECAM_L & allFormats)
		{
			formatToSet = AnalogVideo_SECAM_L;
		}
		else
		{
			formatToSet = AnalogVideo_SECAM_L1;
		}
	}

	if (formatToSet != 0)
	{
		IAMAnalogVideoDecoder *	pVideoDecoder = GetAnalogDecoder();
		if (pVideoDecoder)
		{
			pVideoDecoder->put_TVFormat(formatToSet);
		}
	}
}

long CAnalogInputFilters::GetAllTVFormats(void)
{
	long allFormats = 0;
	IAMAnalogVideoDecoder *	pVideoDecoder = GetAnalogDecoder();
	if (pVideoDecoder)
	{
		pVideoDecoder->get_AvailableTVFormats(&allFormats);
	}
	return allFormats;
}

IAMAnalogVideoDecoder * CAnalogInputFilters::GetAnalogDecoder(void)
{
	IAMAnalogVideoDecoder *	pVideoDecoder = NULL;
	if (mVideoCapture && mVideoCapture->GetFilter())
	{
		mVideoCapture->GetFilter()->QueryInterface(IID_IAMAnalogVideoDecoder, 
			(void**)&pVideoDecoder);
		if (pVideoDecoder)
		{
			pVideoDecoder->Release();
			return pVideoDecoder;
		}
	}
	return NULL;
}

IAMStreamConfig * CAnalogInputFilters::GetStreamConfig(const GUID * inCategory)
{
	IAMStreamConfig * pConfig = NULL;
	if (mGraphBuilder != NULL)
	{
		mGraphBuilder->FindInterface(
			inCategory,					  
			&MEDIATYPE_Video, 
			mVideoCapture->GetFilter(),
			IID_IAMStreamConfig, 
			(void **)&pConfig
			);
	}

	if (pConfig)
	{
		pConfig->Release();
	}
	return pConfig;
}

///////////////////////////// Audio Connector ////////////////////////////
long CAnalogInputFilters::GetAudioConnectorCount(void)
{
	if (mAudioCapture && mAudioCapture->GetFilter())
	{
		return mAudioCapture->GetConnectorCount();
	}
	return 0;
}

CString CAnalogInputFilters::GetAudioConnectorName(long inIndex)
{
	if (mAudioCapture && mAudioCapture->GetFilter())
	{
		return mAudioCapture->GetConnectorName(inIndex);
	}
	return "";
}

void CAnalogInputFilters::SetAudioConnector(long inIndex)
{
	if (mAudioCapture && mAudioCapture->GetFilter())
	{
		mAudioCapture->SetConnector(inIndex);
	}
}

void CAnalogInputFilters::SetAudioMixLevel(double inLevel)
{
	if (mAudioCapture && mAudioCapture->GetFilter())
	{
		mAudioCapture->SetMixLevel(inLevel);
	}
}

void CAnalogInputFilters::ShowVideoCapturePropertyPage(void)
{
	UDsUtils::ShowFilterPropertyPage(mVideoCapture->GetFilter());
}

BOOL CAnalogInputFilters::IsActiveDeviceLost(IUnknown * pLost)
{
	if (mVideoCapture && mVideoCapture->GetFilter())
	{
		IUnknown * pDevice = NULL;
		mVideoCapture->GetFilter()->QueryInterface(IID_IUnknown, (void**)&pDevice);
		pDevice->Release();
		if (::IsEqualObject(pDevice, pLost))
		{
			return TRUE;
		}
	}

	return FALSE;
}

////////////////////////// Image adjusting /////////////////////////////////////
BOOL CAnalogInputFilters::ImageAdjust_GetRange(long Property, long *pMin, 
											   long *pMax, long *pSteppingDelta, 
											   long *pDefault, long *pCapsFlags)
{
	if (mVideoCapture && mVideoCapture->GetFilter())
	{
		IAMVideoProcAmp * pAmp = NULL;
		mVideoCapture->GetFilter()->QueryInterface(IID_IAMVideoProcAmp, 
			(void**)&pAmp);
		if (pAmp)
		{
			HRESULT hr = pAmp->GetRange(Property, pMin, pMax, 
				pSteppingDelta, pDefault, pCapsFlags);
			pAmp->Release();
			return SUCCEEDED(hr);
		}
	}
	return FALSE;
}

BOOL CAnalogInputFilters::ImageAdjust_Set(long Property, long lValue, long Flags)
{
	if (mVideoCapture && mVideoCapture->GetFilter())
	{
		IAMVideoProcAmp * pAmp = NULL;
		mVideoCapture->GetFilter()->QueryInterface(IID_IAMVideoProcAmp, 
			(void**)&pAmp);
		if (pAmp)
		{
			HRESULT hr = pAmp->Set(Property, lValue, Flags);
			pAmp->Release();
			return SUCCEEDED(hr);
		}
	}
	return FALSE;
}

BOOL CAnalogInputFilters::ImageAdjust_Get(long Property, long *lValue, long *Flags)
{
	if (mVideoCapture && mVideoCapture->GetFilter())
	{
		IAMVideoProcAmp * pAmp = NULL;
		mVideoCapture->GetFilter()->QueryInterface(IID_IAMVideoProcAmp, 
			(void**)&pAmp);
		if (pAmp)
		{
			HRESULT hr = pAmp->Get(Property, lValue, Flags);
			pAmp->Release();
			return SUCCEEDED(hr);
		}
	}
	return FALSE;
}

///////////////////////////// VFW setting dialogs ///////////////////////////
BOOL CAnalogInputFilters::VFWHasDialog(int inDlgType)
{
	if (mVideoCapture && mVideoCapture->GetFilter())
	{
		IAMVfwCaptureDialogs * pVfw = NULL;
		mVideoCapture->GetFilter()->QueryInterface(IID_IAMVfwCaptureDialogs, 
			(void**)&pVfw);
		if (pVfw)
		{
			pVfw->Release();
			if (pVfw->HasDialog(inDlgType) == S_OK)
			{
				return TRUE;
			}
		}
	}
	return FALSE;
}

void CAnalogInputFilters::VFWShowDialog(int inDlgType, HWND hwnd)
{
	if (mGraph)
	{
		BOOL isStopped = mGraph->IsStopped();
		if (!isStopped)
		{
			mGraph->Stop();
		}

		IAMVfwCaptureDialogs * pVfw = NULL;
		mVideoCapture->GetFilter()->QueryInterface(IID_IAMVfwCaptureDialogs, 
			(void**)&pVfw);
		if (pVfw)
		{
			pVfw->Release();
			pVfw->ShowDialog(inDlgType, hwnd);
		}

		if (!isStopped)
		{
			mGraph->Run();
		}
	}
}
